1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.beans.factory.support.security;
18
19 import java.lang.reflect.Method;
20 import java.net.URL;
21 import java.security.AccessControlContext;
22 import java.security.AccessController;
23 import java.security.Permissions;
24 import java.security.Policy;
25 import java.security.Principal;
26 import java.security.PrivilegedAction;
27 import java.security.PrivilegedExceptionAction;
28 import java.security.ProtectionDomain;
29 import java.util.PropertyPermission;
30 import java.util.Set;
31 import javax.security.auth.AuthPermission;
32 import javax.security.auth.Subject;
33
34 import org.junit.Before;
35 import org.junit.Test;
36
37 import org.springframework.beans.BeansException;
38 import org.springframework.beans.factory.BeanClassLoaderAware;
39 import org.springframework.beans.factory.BeanCreationException;
40 import org.springframework.beans.factory.BeanFactory;
41 import org.springframework.beans.factory.BeanFactoryAware;
42 import org.springframework.beans.factory.BeanNameAware;
43 import org.springframework.beans.factory.DisposableBean;
44 import org.springframework.beans.factory.InitializingBean;
45 import org.springframework.beans.factory.SmartFactoryBean;
46 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
47 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
48 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
49 import org.springframework.beans.factory.support.SecurityContextProvider;
50 import org.springframework.beans.factory.support.security.support.ConstructorBean;
51 import org.springframework.beans.factory.support.security.support.CustomCallbackBean;
52 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
53 import org.springframework.core.io.DefaultResourceLoader;
54 import org.springframework.core.io.Resource;
55
56 import static org.junit.Assert.*;
57
58
59
60
61
62
63
64
65
66
67
68 public class CallbacksSecurityTests {
69
70 private DefaultListableBeanFactory beanFactory;
71 private SecurityContextProvider provider;
72
73 @SuppressWarnings("unused")
74 private static class NonPrivilegedBean {
75
76 private String expectedName;
77 public static boolean destroyed = false;
78
79 public NonPrivilegedBean(String expected) {
80 this.expectedName = expected;
81 checkCurrentContext();
82 }
83
84 public void init() {
85 checkCurrentContext();
86 }
87
88 public void destroy() {
89 checkCurrentContext();
90 destroyed = true;
91 }
92
93 public void setProperty(Object value) {
94 checkCurrentContext();
95 }
96
97 public Object getProperty() {
98 checkCurrentContext();
99 return null;
100 }
101
102 public void setListProperty(Object value) {
103 checkCurrentContext();
104 }
105
106 public Object getListProperty() {
107 checkCurrentContext();
108 return null;
109 }
110
111 private void checkCurrentContext() {
112 assertEquals(expectedName, getCurrentSubjectName());
113 }
114 }
115
116 @SuppressWarnings("unused")
117 private static class NonPrivilegedSpringCallbacksBean implements
118 InitializingBean, DisposableBean, BeanClassLoaderAware,
119 BeanFactoryAware, BeanNameAware {
120
121 private String expectedName;
122 public static boolean destroyed = false;
123
124 public NonPrivilegedSpringCallbacksBean(String expected) {
125 this.expectedName = expected;
126 checkCurrentContext();
127 }
128
129 @Override
130 public void afterPropertiesSet() {
131 checkCurrentContext();
132 }
133
134 @Override
135 public void destroy() {
136 checkCurrentContext();
137 destroyed = true;
138 }
139
140 @Override
141 public void setBeanName(String name) {
142 checkCurrentContext();
143 }
144
145 @Override
146 public void setBeanClassLoader(ClassLoader classLoader) {
147 checkCurrentContext();
148 }
149
150 @Override
151 public void setBeanFactory(BeanFactory beanFactory)
152 throws BeansException {
153 checkCurrentContext();
154 }
155
156 private void checkCurrentContext() {
157 assertEquals(expectedName, getCurrentSubjectName());
158 }
159 }
160
161 @SuppressWarnings("unused")
162 private static class NonPrivilegedFactoryBean implements SmartFactoryBean {
163 private String expectedName;
164
165 public NonPrivilegedFactoryBean(String expected) {
166 this.expectedName = expected;
167 checkCurrentContext();
168 }
169
170 @Override
171 public boolean isEagerInit() {
172 checkCurrentContext();
173 return false;
174 }
175
176 @Override
177 public boolean isPrototype() {
178 checkCurrentContext();
179 return true;
180 }
181
182 @Override
183 public Object getObject() throws Exception {
184 checkCurrentContext();
185 return new Object();
186 }
187
188 @Override
189 public Class getObjectType() {
190 checkCurrentContext();
191 return Object.class;
192 }
193
194 @Override
195 public boolean isSingleton() {
196 checkCurrentContext();
197 return false;
198 }
199
200 private void checkCurrentContext() {
201 assertEquals(expectedName, getCurrentSubjectName());
202 }
203 }
204
205 @SuppressWarnings("unused")
206 private static class NonPrivilegedFactory {
207
208 private final String expectedName;
209
210 public NonPrivilegedFactory(String expected) {
211 this.expectedName = expected;
212 assertEquals(expectedName, getCurrentSubjectName());
213 }
214
215 public static Object makeStaticInstance(String expectedName) {
216 assertEquals(expectedName, getCurrentSubjectName());
217 return new Object();
218 }
219
220 public Object makeInstance() {
221 assertEquals(expectedName, getCurrentSubjectName());
222 return new Object();
223 }
224 }
225
226 private static String getCurrentSubjectName() {
227 final AccessControlContext acc = AccessController.getContext();
228
229 return AccessController.doPrivileged(new PrivilegedAction<String>() {
230
231 @Override
232 public String run() {
233 Subject subject = Subject.getSubject(acc);
234 if (subject == null) {
235 return null;
236 }
237
238 Set<Principal> principals = subject.getPrincipals();
239
240 if (principals == null) {
241 return null;
242 }
243 for (Principal p : principals) {
244 return p.getName();
245 }
246 return null;
247 }
248 });
249 }
250
251 private static class TestPrincipal implements Principal {
252
253 private String name;
254
255 public TestPrincipal(String name) {
256 this.name = name;
257 }
258
259 @Override
260 public String getName() {
261 return this.name;
262 }
263
264 @Override
265 public boolean equals(Object obj) {
266 if (obj == this) {
267 return true;
268 }
269 if (!(obj instanceof TestPrincipal)) {
270 return false;
271 }
272 TestPrincipal p = (TestPrincipal) obj;
273 return this.name.equals(p.name);
274 }
275
276 @Override
277 public int hashCode() {
278 return this.name.hashCode();
279 }
280 }
281
282 public CallbacksSecurityTests() {
283
284 if (System.getSecurityManager() == null) {
285 Policy policy = Policy.getPolicy();
286 URL policyURL = getClass()
287 .getResource(
288 "/org/springframework/beans/factory/support/security/policy.all");
289 System.setProperty("java.security.policy", policyURL.toString());
290 System.setProperty("policy.allowSystemProperty", "true");
291 policy.refresh();
292
293 System.setSecurityManager(new SecurityManager());
294 }
295 }
296
297 @Before
298 public void setUp() throws Exception {
299
300 final ProtectionDomain empty = new ProtectionDomain(null,
301 new Permissions());
302
303 provider = new SecurityContextProvider() {
304 private final AccessControlContext acc = new AccessControlContext(
305 new ProtectionDomain[] { empty });
306
307 @Override
308 public AccessControlContext getAccessControlContext() {
309 return acc;
310 }
311 };
312
313 DefaultResourceLoader drl = new DefaultResourceLoader();
314 Resource config = drl
315 .getResource("/org/springframework/beans/factory/support/security/callbacks.xml");
316 beanFactory = new DefaultListableBeanFactory();
317 new XmlBeanDefinitionReader(beanFactory).loadBeanDefinitions(config);
318 beanFactory.setSecurityContextProvider(provider);
319 }
320
321 @Test
322 public void testSecuritySanity() throws Exception {
323 AccessControlContext acc = provider.getAccessControlContext();
324 try {
325 acc.checkPermission(new PropertyPermission("*", "read"));
326 fail("Acc should not have any permissions");
327 } catch (SecurityException se) {
328
329 }
330
331 final CustomCallbackBean bean = new CustomCallbackBean();
332 final Method method = bean.getClass().getMethod("destroy");
333 method.setAccessible(true);
334
335 try {
336 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
337
338 @Override
339 public Object run() throws Exception {
340 method.invoke(bean);
341 return null;
342 }
343 }, acc);
344 fail("expected security exception");
345 } catch (Exception ex) {
346 }
347
348 final Class<ConstructorBean> cl = ConstructorBean.class;
349 try {
350 AccessController.doPrivileged(
351 new PrivilegedExceptionAction<Object>() {
352
353 @Override
354 public Object run() throws Exception {
355 return cl.newInstance();
356 }
357 }, acc);
358 fail("expected security exception");
359 } catch (Exception ex) {
360 }
361 }
362
363 @Test
364 public void testSpringInitBean() throws Exception {
365 try {
366 beanFactory.getBean("spring-init");
367 fail("expected security exception");
368 } catch (BeanCreationException ex) {
369 assertTrue(ex.getCause() instanceof SecurityException);
370 }
371 }
372
373 @Test
374 public void testCustomInitBean() throws Exception {
375 try {
376 beanFactory.getBean("custom-init");
377 fail("expected security exception");
378 } catch (BeanCreationException ex) {
379 assertTrue(ex.getCause() instanceof SecurityException);
380 }
381 }
382
383 @Test
384 public void testSpringDestroyBean() throws Exception {
385 beanFactory.getBean("spring-destroy");
386 beanFactory.destroySingletons();
387 assertNull(System.getProperty("security.destroy"));
388 }
389
390 @Test
391 public void testCustomDestroyBean() throws Exception {
392 beanFactory.getBean("custom-destroy");
393 beanFactory.destroySingletons();
394 assertNull(System.getProperty("security.destroy"));
395 }
396
397 @Test
398 public void testCustomFactoryObject() throws Exception {
399 try {
400 beanFactory.getBean("spring-factory");
401 fail("expected security exception");
402 } catch (BeanCreationException ex) {
403 assertTrue(ex.getCause() instanceof SecurityException);
404 }
405
406 }
407
408 @Test
409 public void testCustomFactoryType() throws Exception {
410 assertNull(beanFactory.getType("spring-factory"));
411 assertNull(System.getProperty("factory.object.type"));
412 }
413
414 @Test
415 public void testCustomStaticFactoryMethod() throws Exception {
416 try {
417 beanFactory.getBean("custom-static-factory-method");
418 fail("expected security exception");
419 } catch (BeanCreationException ex) {
420 assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
421 }
422 }
423
424 @Test
425 public void testCustomInstanceFactoryMethod() throws Exception {
426 try {
427 beanFactory.getBean("custom-factory-method");
428 fail("expected security exception");
429 } catch (BeanCreationException ex) {
430 assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
431 }
432 }
433
434 @Test
435 public void testTrustedFactoryMethod() throws Exception {
436 try {
437 beanFactory.getBean("privileged-static-factory-method");
438 fail("expected security exception");
439 } catch (BeanCreationException ex) {
440 assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
441 }
442 }
443
444 @Test
445 public void testConstructor() throws Exception {
446 try {
447 beanFactory.getBean("constructor");
448 fail("expected security exception");
449 } catch (BeanCreationException ex) {
450
451 assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
452 }
453 }
454
455 @Test
456 public void testContainerPrivileges() throws Exception {
457 AccessControlContext acc = provider.getAccessControlContext();
458
459 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
460
461 @Override
462 public Object run() throws Exception {
463 beanFactory.getBean("working-factory-method");
464 beanFactory.getBean("container-execution");
465 return null;
466 }
467 }, acc);
468 }
469
470 @Test
471 public void testPropertyInjection() throws Exception {
472 try {
473 beanFactory.getBean("property-injection");
474 fail("expected security exception");
475 } catch (BeanCreationException ex) {
476 assertTrue(ex.getMessage().contains("security"));
477 }
478
479 beanFactory.getBean("working-property-injection");
480 }
481
482 @Test
483 public void testInitSecurityAwarePrototypeBean() {
484 final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
485 BeanDefinitionBuilder bdb = BeanDefinitionBuilder
486 .genericBeanDefinition(NonPrivilegedBean.class).setScope(
487 ConfigurableBeanFactory.SCOPE_PROTOTYPE)
488 .setInitMethodName("init").setDestroyMethodName("destroy")
489 .addConstructorArgValue("user1");
490 lbf.registerBeanDefinition("test", bdb.getBeanDefinition());
491 final Subject subject = new Subject();
492 subject.getPrincipals().add(new TestPrincipal("user1"));
493
494 NonPrivilegedBean bean = Subject.doAsPrivileged(
495 subject, new PrivilegedAction<NonPrivilegedBean>() {
496 @Override
497 public NonPrivilegedBean run() {
498 return lbf.getBean("test", NonPrivilegedBean.class);
499 }
500 }, null);
501 assertNotNull(bean);
502 }
503
504 @Test
505 public void testTrustedExecution() throws Exception {
506 beanFactory.setSecurityContextProvider(null);
507
508 Permissions perms = new Permissions();
509 perms.add(new AuthPermission("getSubject"));
510 ProtectionDomain pd = new ProtectionDomain(null, perms);
511
512 new AccessControlContext(new ProtectionDomain[] { pd });
513
514 final Subject subject = new Subject();
515 subject.getPrincipals().add(new TestPrincipal("user1"));
516
517
518 Subject.doAsPrivileged(subject, new PrivilegedAction<Object>() {
519
520 @Override
521 public Object run() {
522
523 assertEquals("user1", getCurrentSubjectName());
524 assertEquals(false, NonPrivilegedBean.destroyed);
525
526 beanFactory.getBean("trusted-spring-callbacks");
527 beanFactory.getBean("trusted-custom-init-destroy");
528
529 beanFactory.getBean("trusted-spring-factory");
530 beanFactory.getBean("trusted-spring-factory");
531 beanFactory.getBean("trusted-spring-factory");
532
533 beanFactory.getBean("trusted-factory-bean");
534 beanFactory.getBean("trusted-static-factory-method");
535 beanFactory.getBean("trusted-factory-method");
536 beanFactory.getBean("trusted-property-injection");
537 beanFactory.getBean("trusted-working-property-injection");
538
539 beanFactory.destroySingletons();
540 assertEquals(true, NonPrivilegedBean.destroyed);
541 return null;
542 }
543 }, provider.getAccessControlContext());
544 }
545 }